package com.easy.robot.task

import ai.easy.robot.task.ITask
import ai.easy.robot.task.InterruptComingSelector
import ai.easy.robot.utils.logd
import android.os.Bundle
import kotlinx.coroutines.experimental.Deferred
import kotlinx.coroutines.experimental.delay
import kotlinx.coroutines.experimental.runBlocking
import java.util.*
import kotlin.coroutines.experimental.CoroutineContext

/**
 * 负责任务调度，让任务有序地执行, 维持各个任务的生命周期
 */
class TaskPool {

    var idleTask: ITask? = null
        set(value) {
            if (value == null) {
                field = BaseIdleTask()
            } else {
                field = value
            }
        }

    var myIdleTask: ITask = idleTask ?: BaseIdleTask()


    private val taskStack: Stack<TaskTableItem> = Stack()

    internal data class TaskTableItem(
            val name: String, val task: ITask, val ctx: TaskContext,
            val startData: Bundle? = null,
            val addedTime: Long,
            var startTime: Long = -1, //开始时间,用于延时任务
            var pauseTime: Long = -1,
            var canInterrupted: Boolean = true,
            var forceStop: Boolean = false
            , var priority: Int = 0
    )

    private val waitingTask: LinkedList<TaskTableItem> = LinkedList()  //LinkedList()

//    inline fun <T> MutableList<T>.peek():T? = synchronized(this){
//            get(0)
//        }
//    inline fun <T> MutableList<T>.poll(): T? = synchronized(this){
//        removeAt(0)
//    }

//    inline fun <T> MutableList<T>.offer(x: T):Unit = synchronized(this){
//        add(x)
//    }


    var isIdle = false

    private var looping = true

    /**
     * 任务调度器的日志接口
     */
    var logger: ((String) -> Unit)? = null

    internal fun log(txt: String) {
        logger?.invoke("$txt")
    }

    //private var mainCoContext:CoroutineContext? = null

    /**
     * 主循环
     */
    fun mainLoop() {
        runBlocking {
            //mainCoContext = context
            looping = true
            logd("TaskPool start")
            mainLoop0(context)
            logd("TaskPool stop")
        }
    }

    var interruptComingSelector: InterruptComingSelector? = null

    var askJob: Deferred<Unit>? = null

    private inline fun checkOutDate(ti: TaskTableItem): Boolean = (System.currentTimeMillis() - ti.addedTime) > 300000L    //5 min 前的任务为失效任务

    private suspend fun mainLoop0(context: CoroutineContext) {

        val idleCtx = TaskContext(this)
        idleCtx.cc = context

        while (looping) {

            //是否有新任务
            if (waitingTask.size > 0) {
                val ti = waitingTask.peek()
                //检测任务添加时间是否失效
                if (checkOutDate(ti!!)) {
                    waitingTask.poll()
                    continue
                }

                val wanna_task = ti.task  //
                //
                if (isIdle) {
                    myIdleTask.onStop(idleCtx)
                    log("Idle任务停止")
                    isIdle = false
                    val ctx = ti.ctx
                    ctx.startData = ti.startData ?: idleCtx.startData
                    ctx.cc = context
                    //
                    idleCtx.release()
                    log("${wanna_task.name}任务开始")
                    waitingTask.poll()
                    wanna_task.onStart(ctx)
                } else if (taskStack.size > 0) {
                    //当前有任务在运行
                    val cur = taskStack.peek()
                    val cur_task = cur.task
                    val cur_ctx = cur.ctx
                    //当前任务不可打断
                    if (!cur.canInterrupted && cur_task.isAlive) {
                        delay(20)
                        continue
                    }

                    //
                    if (cur_task.canResume() && cur_task.isAlive && !cur.forceStop) {
                        cur_task.onPause(cur_ctx)
                        log("${cur_task.name}任务暂停")
                    } else {

                        //
                        cur_task.onStop(cur_ctx)
                        log("${cur_task.name}任务停止")
                        cur_ctx.release()
                        taskStack.pop()
                        //
                    }
                    //
                    ti.ctx.startData = ti.startData ?: cur_ctx.startData
                    ti.ctx.cc = context
                    log("${wanna_task.name}任务开始")
                    waitingTask.poll()
                    wanna_task.onStart(ti.ctx)
                }
                //将可恢复任务压入堆栈
                taskStack.push(ti)
                //
                continue
            }

            //没有新任务时

            //检查当前是否还有任务，弹出失效的任务
            if (taskStack.size > 0) {
                val cur = taskStack.peek()
                val cur_task = cur.task
                val cur_ctx = cur.ctx
                if (!cur_task.isAlive) {

                    cur_task.onStop(cur_ctx)
                    log("${cur_task.name}任务停止")
                    //任务已停止，弹出
                    taskStack.pop()
                    cur_ctx.release()
                    //
                    if (taskStack.size > 0) {
                        taskStack.peek().let {
                            log("${it.task.name}任务恢复")
                            it.task.onResume(it.ctx)
                        }
                    }
                    //
                    continue
                }
            }

            //无任何任务，转入空闲状态
            if (taskStack.size == 0) {
                if (!isIdle) {
                    log("Idle任务开始")
                    idleTask?.onStart(idleCtx)
                    isIdle = true
                }
            }
            //
            delay(25)  //挂起防止线程堵塞

        }

        clearAllTask()

    }

    /**
     * 结束
     */
    fun endLoop() {
        looping = false
    }

    fun clearAllTask() {
        waitingTask.clear()
        //检查当前是否有任务，弹出失效的任务
        while (taskStack.size > 0) {
            val cur = taskStack.peek()
            val cur_task = cur.task
            val cur_ctx = cur.ctx
            if (!cur_task.isAlive) {
                cur_task.onStop(cur_ctx)
                log("${cur_task.name}任务停止")
                cur_ctx.release()
                taskStack.pop()
                continue
            } else {
                // delay moments
                break
            }
        }
    }

    /**
     * 当前有任务执行且不可打断
     */
    fun isCurrentTaskCannotInterrupted(): Boolean = if (taskStack.empty()) {
        false
    } else {
        taskStack.peek()?.let { it.task.isAlive && !it.canInterrupted } ?: false
    }

    //
//    if(null==askJob) {
//        askJob = async(context) {
//            log("${cur_task.name}任务不可打断")
//            //var yes=false
//            try {
//                withTimeout(30, TimeUnit.SECONDS) {
//                    val sel = interruptComingSelector?.makeSelection("${cur_task.name}")?:false
//                    if(sel){
//                        cur.canInterrupted = true
//                    }
//                }
//            }catch (ex:Exception){
//                ex.printStackTrace()
//                //yes = false
//            }finally {
//                //
//                interruptComingSelector?.onFinishOrCancel()
//                // TODO 通知新任务加入
//            }
//            //yes
//        }
//    }


    /**
     * 添加新任务
     * @param task 实现ITask的对象
     * @param startData 任务启动参数
     * @param canInterrupted 任务是否可以被打断
     * @param priority 任务优先级, 越大越优先
     */
    @JvmOverloads
    fun addNewTask(task: ITask, startData: Bundle? = null, canInterrupted: Boolean = true, priority: Int = 0) {
        val ctx = TaskContext(this)
        startData?.let { ctx.startData = it }
        val now = System.currentTimeMillis()

        val item = TaskTableItem(task.name, task, ctx, startData = startData, addedTime = now, canInterrupted = canInterrupted,
                priority = priority)
        //
        synchronized(this) {
            if (isCurrentTaskCannotInterrupted()) {
                //
                val ti = taskStack.peek()
                //
                log("任务 ${ti.name} 不可打断")
                ti.ctx.askInterrupt(ti.name, ti.task.canResume()) { userChoice ->
                    if (userChoice > 0) {
                        ti.canInterrupted = true
                    }
                    if (userChoice == InterruptComingSelector.CHOICE_STOP) {
                        ti.forceStop = true
                    }
                    //通知新任务加入
                    addNewTask(item)
                }

            } else {
                addNewTask(item)
            }
        }
    }

    internal fun addNewTask(item: TaskTableItem) {
        //insert item to queue sorted by priority
        synchronized(waitingTask) {
            val n = waitingTask.size
            if (n > 1) {
                var ii = n - 1  //the index to insert
                for (k in n - 1..0) {
                    if (item.priority < waitingTask[k].priority) {
                        ii = k
                    }
                }
                waitingTask.add(ii, item)
            } else {
                waitingTask.add(item)
            }
        }

    }


}